原文地址
https://developer.android.google.cn/reference/android/support/constraint/ConstraintLayout
介绍
ConstrainLayout是一个允许开发者灵活地设置控件的位置和大小的ViewGroup。
只要你使用的Android系统版本在9以上,你便可以通过添加依赖的方式来使用ConstrainLayout.
使用
添加依赖
implementation ‘com.android.support.constraint:constraint-layout:1.1.3’
常用约束
相对定位(Relative positioning)
相对定位是ConstrainLayout构建布局的一种基本方式。相对定位约束可以帮助我们通过一个给定的Widget来摆放另外一个Widget。我们可以在横纵两个方向上约束Widget。
横向: left, right, start and end sides
纵向: top, bottom sides and text baseline
一般思路是将一个 Widget的给定侧约束到其他Widget的另一侧。
比如,把button B放置到button A的右侧(下图)
实现可以如下
1 | <Button android:id="@+id/buttonA" ... /> |
上述代码就是告诉系统,我们想让button B的左侧约束到button A的右侧。这样一个位置约束意味着,系统将让button A的右侧和button B的左侧在X轴上具有相同的位置。
此类相对位置属性还有很多,具体如下:
- layout_constraintLeft_toLeftOf
- layout_constraintLeft_toRightOf
- layout_constraintRight_toLeftOf
- layout_constraintRight_toRightOf
- layout_constraintTop_toTopOf
- layout_constraintTop_toBottomOf
- layout_constraintBottom_toTopOf
- layout_constraintBottom_toBottomOf
- layout_constraintBaseline_toBaselineOf
- layout_constraintStart_toEndOf
- layout_constraintStart_toStartOf
- layout_constraintEnd_toStartOf
- layout_constraintEnd_toEndOf
这些属性通过引用id来代表一个Widget,或者使用parent来代表父布局
1 | <Button android:id="@+id/buttonB" ... |
边距(Margins)
如果设置了边距,则它们将应用于相应的约束,将边距强制设置为目标Widget和源Widget之间的空间。通常的布局边距属性就可以达到此效果。
- android:layout_marginStart
- android:layout_marginEnd
- android:layout_marginLeft
- android:layout_marginTop
- android:layout_marginRight
- android:layout_marginBottom
注意: 边距只能是正数或等于零,采用Dimension形式。
约束目标GONE后边距处理 (Margins when connected to a GONE widget)
当约束目标的可见性为View.GONE时,你还可以使用以下属性指示要使用的不同边距值:
- layout_goneMarginStart
- layout_goneMarginEnd
- layout_goneMarginLeft
- layout_goneMarginTop
- layout_goneMarginRight
- layout_goneMarginBottom
居中定位和位置偏差
ConstraintLayout的一个有用方面是它如何处理“不可能”的约束。例如,如果我们有如下代码:
1 | <android.support.constraint.ConstraintLayout ...> |
除非ConstraintLayout恰好具有与Button完全相同的大小,否则两个约束不能同时满足(双方都不能成为我们想要它们的位置)。
在这种情况下,约束的作用就像是相反的力量将Widget拉平(上图);这样Widget最终将会在父容器中居中显示。这种使用方式在纵轴方向上同样适用。
偏差(Bias)
遇到这种相反的约束时的默认设置是使Widget居中;但是你可以使用偏差属性调整定位以使一侧偏向另一侧。
- layout_constraintHorizontal_bias
- layout_constraintVertical_bias
例如,如下代码将使左侧具有30%的偏差而不是默认的50%,使得左侧将更短,Widget更倾向于左侧(具体效果如下图):
1 | <android.support.constraint.ConstraintLayout ...> |
使用偏差属性,你可以制作更好地适应屏幕尺寸变化的用户界面。
环形定位(Circular positioning (Added in 1.1))
你可以以距离或者角度来约束一个Widget中心相对于另一个Widget的中心。这样我们就可以将Widget放置到一个圆环上。具体属性如下:
- layout_constraintCircle : 引用widget ID
- layout_constraintCircleRadius : 到另一个widget的距离
- layout_constraintCircleAngle : widget需要摆放在哪个角度 (0-360)
1 | <Button android:id="@+id/buttonA" ... /> |
可见性行为(Visibility behavior)
ConstraintLayout对于可见性为View.GONE的Widget有明确的处理方式。
GONE widget,一般情况下,将不会显示在界面上,同时也不再是布局中的一部分。
但就布局计算而言,GONE Widget仍然是其中的一部分,这是有很大区别的。
- 对于布局传递,它们的尺寸将被视为零(基本上,它们将被解析为一个点)
- 如果他们对其他Widget有限制,这些限制仍然会得到体现,但任何边距都会等于零
这种特定的行为可以满足你在不破坏布局的情况下构建布局,只需要暂时将对应的Widget标记为GONE即可,这在构建简单的布局动画时是很有用的。
如上图,当A GONE后,B使用的左边距是B相对于A的边距。在某些情况下,这个边距可能并不是你所需要的(比如,A相对于容器存在20dp的左边距,B相对于A有40dp的左边距,当A被标记为GONE后,B相对于容器就会存在40dp的左边距)。因此,你可以指定在连接到的Widget标记为GONE时的margin作为备用边距值。具体看上一章节的【约束目标GONE后边距处理】。
尺寸约束(Dimensions constraints)
ConstraintLayout最小尺寸和最大尺寸
通过如下属性你可以给ConstrainLayout定义最大或是最小尺寸。
- android:minWidth set the minimum width for the layout
- android:minHeight set the minimum height for the layout
- android:maxWidth set the maximum width for the layout
- android:maxHeight set the maximum height for the layout
当其尺寸设置为WRAP_CONTENT时,这些最小和最大尺寸将会被ConstraintLayout使用到。
Widgets尺寸约束
Widgets的尺寸需要通过如下三种方式设置android:layout_width和android:layout_height来明确。
- 使用一个明确的尺寸大小 (数字值如123dp或者是一个尺寸引用)
- 使用WRAP_CONTENT, 让控件自己计算其大小
- 使用0dp, 等价于 “MATCH_CONSTRAINT”
前两种设置的效果和其他布局一样。最后一个将以匹配所设置的约束的方式调整Widget的大小(上图中(a)wrap_content,(b)0dp)。如果设置来边距,它们也将被计算在内(上图中(c)0dp with margin)。
重要 针对ConstrainLayout中的Widget,我们不推荐使用MATCH_PARENT。我们可以通过使用MATCH_CONSTRAINT配合约束 Widget 的left/right或者top/bottom 到“parent”来定义类似的行为。
WRAP_CONTENT:强制执行约束 (Added in 1.1)
如果一个尺寸设置为WRAP_CONTENT,在1.1版本之前,他们将会被定义为数值类的尺寸大小,约束将不会限制结果尺寸。一般情况下这样已经足够满足需求并且运行速度也是很快的,但是在某些情况下,你可能想用WRAP_CONTENT来设置尺寸,同时也想强制约束来限制结果布局尺寸。这种情况下,你可以使用如下属性:
- app:layout_constrainedWidth=”true|false”
- app:layout_constrainedHeight=”true|false”
MATCH_CONSTRAINT(Added in 1.1)
当Widget的尺寸被设置为MATCH_CONSTRAINT时,默认的结果就是使用所有可用的空间。如下几个额外的属性可以被使用到:
- layout_constraintWidth_min and layout_constraintHeight_min : 将为这个尺寸设置最小值
- layout_constraintWidth_max and layout_constraintHeight_max : 将为这个尺寸设置最大值
- layout_constraintWidth_percent and layout_constraintHeight_percent : 将按相对父布局的百分比来设置尺寸
最小值和最大值(Min and Max)
为min和max指示的值可以是Dp单位,也可以是“wrap”,它将使用与WRAP_CONTENT将执行的值相同的值
百分比尺寸(Percent dimension)
要使用百分比,你需要做如下配置:
- 尺寸设置为MATCH_CONSTRAINT(0dp)
- 默认值设置为percent** app:layout_constraintWidth_default=”percent”** 或者app:layout_constraintHeight_default=”percent”
(备注: 在版本1.1-beta1 and 1.1-beta2中这些配置是需要的, 但是在后续的版本中只要百分比属性被定义,便不再需要这些配置) - 然后设置layout_constraintWidth_percent或者 layout_constraintHeight_percent属性值,范围0-1
比率
你可以定义Widget的宽高比例。为了实现这个效果,宽高中至少又一个设置为0dp(i.e.,MATCH_CONSTRAINT), 然后给** layout_constraintDimensionRatio**指定一个比例值,如下
1 | <Button android:layout_width="wrap_content" |
这段代码将设置button的宽高一样。比例值可以通过如下两种方式设置:
- float值, 代表宽高的比例
- 比例值按照“width:height”的格式书写
在宽高都设置为MATCH_CONSTRAINT(0dp)时,我们仍然能够使用比例属性。在这种情况下,系统设置满足所有约束的最大尺寸并保持指定的纵横比。要根据另一个的尺寸约束一个特定边,可以预先附加“W,”或“H,”分别约束宽度或高度。比如,一个尺寸被两个目标约束(宽度0dp并且在父布局居中),你可以通过在比例值前添加“W(约束宽度)”或者“H(约束高度)”,来指明约束宽度或者高度。
1 | <Button android:layout_width="0dp" |
如上代码,将按照16:9的比例来设置button的高度,而宽度将匹配父布局的约束。也就是这种情况下宽度:高度=16:9,由宽度来决定高度。
链(chain)
链在单个轴(水平或垂直)上提供组群行为。另一个轴可以独立约束
创建一个链
如果一组Widgets通过双向连接链接在一起,则它们被视为链。(下图展示的是一个由两个Widget组成的最小的链)
链头
链由在链的第一个元素上设置的属性控制(我们可以将其视为链的“头”)
头部是水平链的最左侧Widget,垂直链的最顶部Widget。
链间边距
如果在双向连接上指定了边距,则他们将会被计算在内。在扩散链的情况下,将从分配的空间中减去这些边距
链Style
在链的第一个元素上设置属性layout_constraintHorizontal_chainStyle或layout_constraintVertical_chainStyle时,链的行为将根据指定的样式更改(默认为CHAIN_SPREAD)
- CHAIN_SPREAD – 元素将等间距散开(默认style)
- Weighted链 – CHAIN_SPREAD 模式, 当一些Widgets设置为MATCH_CONSTRAINT,他们将被分配所有可用空间。
- CHAIN_SPREAD_INSIDE – 相似地, 但是链的两端不会被分配空间。
- CHAIN_PACKED – 链上元素会被打包在一起。子项的水平或垂直偏差属性将影响整个打包元素的定位。
权重链
链的默认行为是在可用空间中平均分布元素。如果一个或多个元素使用MATCH_CONSTRAINT,则它们将使用可用的空白空间(他们之间平等分配)。
layout_constraintHorizontal_weight和layout_constraintVertical_weight属性将控制如何使用MATCH_CONSTRAINT在元素之间分配空间。例如,在使用MATCH_CONSTRAINT的包含两个元素的链上,第一个元素使用权重2,第二个元素使用权重1,第一个元素占用的空间将是第二个元素占用的空间的两倍。
边距和链(1.1版本)
在链中的元素上使用边距时,边距是相加的
例如,在水平链上,如果一个元素定义了10dp的右边距而下一个元素定义了5dp的左边距,则这两个元素之间产生的边距为15dp。
在计算链用于定位项目的剩余空间时,会同时考虑项目及其边距。剩余空间不包含边距。
虚拟助手(Virtual Helper objects)
除了之前详述的内在功能外,您还可以使用ConstraintLayout中的特殊帮助程序对象来帮助您进行布局。现在,Guideline可以帮助你创建相对于ConstraintLayout容器定位的水平和垂直Guideline。然后Widgets可以被约束到这些Guideline上。在1.1版本中,Barrier和Group也别加入进来。
优化器(in 1.1)
在1.1版本中,我们提供约束优化器。你可以通过将标记app:layout_optimizationLevel添加到ConstraintLayout元素来决定应用哪些优化。
- none : 不做任何优化
- standard : 默认值. 只优化 direct 和 barrier 约束
- direct : 优化 direct 约束
- barrier : 优化 barrier 约束
- chain : 优化 chain 约束 (试验版)
- dimensions : 优化 dimensions 测量 (试验版), 减少match constrains元素的测量次数。
此属性是一个掩码,因此您可以通过列出所需的优化来决定打开或关闭特定的优化。例如
1 | app:layout_optimizationLevel="direct|barrier|chain" |